package com.ruoyi.common.config.serializer;

import java.io.IOException;
import java.util.Objects;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.ruoyi.common.annotation.Sensitive;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.DesensitizedType;
import com.ruoyi.common.utils.SecurityUtils;

/**
 * 数据脱敏序列化过滤
 *
 * @author ruoyi
 */
public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {
    private DesensitizedType desensitizedType;

    /**
     * 执行字符串字段的序列化操作，根据是否需要脱敏决定输出原始值还是脱敏后的值
     *
     * @param value       需要序列化的字符串值
     * @param gen         JSON生成器，用于写入序列化结果
     * @param serializers 序列化提供者，包含序列化配置信息
     * @throws IOException 当序列化过程中发生IO异常时抛出
     */
    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        // 根据脱敏条件判断是否需要对数据进行脱敏处理
        if (desensitization()) {
            gen.writeString(desensitizedType.desensitizer().apply(value));
        } else {
            gen.writeString(value);
        }
    }

    /**
     * 创建上下文相关的序列化器实例，根据字段上的@Sensitive注解配置脱敏类型
     *
     * @param prov     序列化提供者，用于获取序列化配置
     * @param property 当前正在处理的Bean属性信息
     * @return 配置好的序列化器实例或默认序列化器
     * @throws JsonMappingException 当JSON映射过程中发生错误时抛出
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
            throws JsonMappingException {
        // 获取字段上的敏感注解配置
        Sensitive annotation = property.getAnnotation(Sensitive.class);
        // 检查是否存在敏感注解且字段类型为String
        if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) {
            this.desensitizedType = annotation.desensitizedType();
            return this;
        }
        // 返回默认的值序列化器
        return prov.findValueSerializer(property.getType(), property);
    }

    /**
     * 判断当前用户是否需要进行数据脱敏处理
     * 管理员用户不需要脱敏，普通用户需要脱敏
     *
     * @return true表示需要脱敏，false表示不需要脱敏
     */
    private boolean desensitization() {
        try {
            LoginUser securityUser = SecurityUtils.getLoginUser();
            // 管理员不脱敏
            return !securityUser.getUser().isAdmin();
        } catch (Exception e) {
            // 发生异常时默认进行脱敏处理
            return true;
        }
    }
}

